package ui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;

import model.City;
import model.Country;
import util.ImagePanel;
import util.PdfFilePrint;
import controller.CityController;
import controller.CountryController;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;

public class CityUI implements ActionListener
{	
	private boolean startup;

	private static CityUI instance = null;

	private CityController cityCtrl;
	private CountryController countryCtrl;

	private JFrame frameCityUI;

	private JTabbedPane tabbedPane;

	private ImagePanel newCities;
	private ImagePanel allCities;

	private Image image = null;

	private JLabel cities;
	private JLabel searchBy;
	private JLabel searchWith;

	private JTable allCitiesTable;

	private DefaultTableModel allCitiesTableModel;

	private JScrollPane allCitiesTableScroll;

	private JComboBox<String> allCitiesComboBoxsearchType;
	private JComboBox<String> newCityCountryComboBoxSearchType;

	private JButton createCity;
	private JButton emptySearchList;
	private JButton editCity;
	private JButton statistics;
	private JButton backButton;
	private JButton btnPrint;

	private JTextField allCitiesSearch;
	private JTextField newCityName;

	private ArrayList<City> cityList;
	private ArrayList<Country> countryList;
	private String allCitiesColumns[] = { "#", "Name", "Country", ""};;

	private backButton back;

	public void display()
	{
		frameCityUI.setSize(700,400);
		frameCityUI.setVisible(true);
		frameCityUI.setResizable(false);
		frameCityUI.setLocationRelativeTo(null);

	}

	public CityUI()
	{

		back = new backButton();
		frameCityUI = new MainWindow();

		cities = new JLabel("CITIES");
		cities.setBounds(9, 1 , 71, 28);
		cities.setForeground(Color.white);
		cities.setFont(new Font("Dialog", Font.BOLD, 20));

		frameCityUI.getContentPane().add(cities);


		createCity = new JButton();
		createCity.setBounds(286, 110, 103, 23);
		createCity.setText("Create City");
		createCity.setOpaque(false);
		createCity.addActionListener(this);

		emptySearchList = new JButton();
		emptySearchList.setBounds(286, 110, 103, 23);
		emptySearchList.setText("Clear Search");
		emptySearchList.setOpaque(false);
		emptySearchList.addActionListener(this);

		editCity = new JButton();
		editCity.setBounds(286, 110, 103, 23);
		editCity.setText("Edit City");
		editCity.setOpaque(false);
		editCity.addActionListener(this);

		statistics = new JButton();
		statistics.setLocation(584, 327);
		statistics.setSize(100, 20);
		statistics.setOpaque(false);
		statistics.setText("Statistics");
		statistics.addActionListener(this);

		backButton = new JButton();
		backButton.setText("Back");
		backButton.setOpaque(false);
		backButton.setBounds(9, 327, 100, 20);
		backButton.addActionListener(this);

		frameCityUI.getContentPane().add(backButton);
		frameCityUI.getContentPane().add(statistics);

		try
		{
			image = ImageIO.read(new File("img/background/background.jpg"));
		}
		catch(Exception e)
		{
			msgError(null, "Could not load background");
		}

		tabbedPane = new JTabbedPane();
		tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
		tabbedPane.setBounds(0, 31, 694, 289);

		frameCityUI.getContentPane().add(tabbedPane);

		cityCtrl = new CityController();
		countryCtrl = new CountryController();

		// new City panel

		allCities = new ImagePanel(image);
		allCities.setBounds(0, 31, 694, 289);

		newCities = new ImagePanel(image);
		newCities.setBounds(0, 31, 694, 289);

		JLabel newCity = new JLabel("City name:");
		JLabel country = new JLabel("Country:");
		searchBy = new JLabel("Search by:");
		searchWith = new JLabel("Search for:");

		newCityName = new JTextField();

		countryList = new ArrayList<Country>();
		try
		{
			countryList = countryCtrl.findCountriesByAllInfo("");
		} catch (SQLException e1)
		{
			msgError(null, "Could not load all countries");
			e1.printStackTrace();
		}

		newCityCountryComboBoxSearchType = new JComboBox<String>();

		for (int i = 0; i < countryList.size(); i++)
		{
			newCityCountryComboBoxSearchType.addItem(countryList.get(i).getName());
		}

		tabbedPane.addTab("All Cities", allCities);

		tabbedPane.addTab("New City", newCities);
		GroupLayout gl_newCities = new GroupLayout(newCities);
		gl_newCities.setHorizontalGroup(
				gl_newCities.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_newCities.createSequentialGroup()
						.addGap(212)
						.addGroup(gl_newCities.createParallelGroup(Alignment.LEADING)
								.addComponent(newCity)
								.addComponent(country))
								.addGap(81)
								.addGroup(gl_newCities.createParallelGroup(Alignment.LEADING, false)
										.addComponent(createCity, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
										.addComponent(newCityCountryComboBoxSearchType, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
										.addComponent(newCityName, GroupLayout.PREFERRED_SIZE, 116, GroupLayout.PREFERRED_SIZE))
										.addContainerGap(228, Short.MAX_VALUE))
				);
		gl_newCities.setVerticalGroup(
				gl_newCities.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_newCities.createSequentialGroup()
						.addGap(54)
						.addGroup(gl_newCities.createParallelGroup(Alignment.BASELINE)
								.addComponent(newCity)
								.addComponent(newCityName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
								.addGap(18)
								.addGroup(gl_newCities.createParallelGroup(Alignment.BASELINE)
										.addComponent(newCityCountryComboBoxSearchType, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
										.addComponent(country))
										.addGap(18)
										.addComponent(createCity)
										.addContainerGap(108, Short.MAX_VALUE))
				);
		newCities.setLayout(gl_newCities);

		allCitiesTableModel = new DefaultTableModel(null, allCitiesColumns);

		allCitiesTable = new JTable(allCitiesTableModel)
		{
			private static final long serialVersionUID = 1L;

			public boolean isCellEditable(int rowIndex, int colIndex) 
			{
				return false;
			}

			public Class<?> getColumnClass(int column)   
			{   
				return getValueAt(0, column).getClass();   
			}  
		};
		Dimension dimension = allCitiesTable.getPreferredSize();
		double width = dimension.width / allCitiesColumns.length;
		double[] width_2 = { 0.3, 1.0, 1.0, 0.3 };

		for(int i = 0; i < allCitiesColumns.length; i++)
			allCitiesTable.getColumnModel().getColumn(i).setPreferredWidth((int) (width*width_2[i])); 

		allCitiesTable.setAutoCreateRowSorter(true);

		allCitiesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		allCitiesTableScroll = new JScrollPane(allCitiesTable);



		allCitiesComboBoxsearchType = new JComboBox<String>();
		allCitiesComboBoxsearchType.addActionListener(this);
		allCitiesComboBoxsearchType.addItem("Everything");
		allCitiesComboBoxsearchType.addItem("Name");
		allCitiesComboBoxsearchType.addItem("Country");

		allCitiesSearch = new JTextField();
		allCitiesSearch.getDocument().addDocumentListener(new DocumentListener()
		{

			@Override
			public void changedUpdate(DocumentEvent arg0)
			{

				searchCities();
			}

			@Override
			public void insertUpdate(DocumentEvent arg0)
			{
				searchCities();
			}

			@Override
			public void removeUpdate(DocumentEvent arg0)
			{
				searchCities();
			}

		}
				);



		GroupLayout gl_allCities = new GroupLayout(allCities);
		gl_allCities.setHorizontalGroup(
				gl_allCities.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_allCities.createSequentialGroup()
						.addContainerGap()
						.addGroup(gl_allCities.createParallelGroup(Alignment.LEADING)
								.addComponent(allCitiesTableScroll, GroupLayout.DEFAULT_SIZE, 669, Short.MAX_VALUE)
								.addGroup(gl_allCities.createSequentialGroup()
										.addGroup(gl_allCities.createParallelGroup(Alignment.LEADING, false)
												.addGroup(gl_allCities.createSequentialGroup()
														.addComponent(searchWith)
														.addPreferredGap(ComponentPlacement.RELATED)
														.addComponent(allCitiesSearch, GroupLayout.PREFERRED_SIZE, 155, GroupLayout.PREFERRED_SIZE))
														.addGroup(gl_allCities.createSequentialGroup()
																.addComponent(searchBy)
																.addPreferredGap(ComponentPlacement.RELATED)
																.addComponent(allCitiesComboBoxsearchType, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
																.addPreferredGap(ComponentPlacement.UNRELATED)
																.addComponent(emptySearchList, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
																.addGap(280)
																.addComponent(editCity, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
																.addContainerGap())
				);
		gl_allCities.setVerticalGroup(
				gl_allCities.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_allCities.createSequentialGroup()
						.addContainerGap()
						.addGroup(gl_allCities.createParallelGroup(Alignment.BASELINE)
								.addComponent(allCitiesComboBoxsearchType, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
								.addComponent(searchBy))
								.addPreferredGap(ComponentPlacement.RELATED)
								.addGroup(gl_allCities.createParallelGroup(Alignment.BASELINE)
										.addComponent(searchWith)
										.addComponent(allCitiesSearch, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
										.addComponent(emptySearchList, GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
										.addComponent(editCity, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
										.addPreferredGap(ComponentPlacement.RELATED)
										.addComponent(allCitiesTableScroll, GroupLayout.PREFERRED_SIZE, 173, GroupLayout.PREFERRED_SIZE)
										.addGap(22))
				);
		allCities.setLayout(gl_allCities);

		btnPrint = new JButton();
		btnPrint.setText("Print");
		btnPrint.setOpaque(false);
		btnPrint.setBounds(474, 327, 100, 20);
		btnPrint.addActionListener(this);
		frameCityUI.getContentPane().add(btnPrint);



		try
		{
			updateCityList();

		}
		catch(Exception e)
		{
			msgError(null, "Could not load information");
		}
	}
	private void updateCityList()
	{
		try
		{
			cityList = cityCtrl.getAllCities();
			allCitiesUpdateTable(cityList);
		}
		catch(Exception e)
		{
			msgError(allCities, "Could not load cities");
		}
	}
	private void updateCountries(JComboBox<String> comboBox)
	{
		comboBox.removeAllItems();

		for(Country country : countryList)
			comboBox.addItem(country.getName());
	}


	@Override
	public void actionPerformed(ActionEvent e)
	{
		frameCityUI.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

		if(e.getSource() == createCity)
		{
			addCity();
		}
		else if(e.getSource() == emptySearchList)
		{
			allCitiesComboBoxsearchType.setSelectedIndex(0);
			allCitiesSearch.setText(null);
		}
		else if(e.getSource() == editCity)
		{
			showEditCityDialog();
		}
		else if(e.getSource() == statistics)
		{
			StatisticsUI stats = StatisticsUI.getInstance();
			stats.display();
			frameCityUI.setVisible(false);
		}
		else if (e.getSource() == allCitiesComboBoxsearchType)
		{
			if(startup)
				searchCities();

		}
		else if(e.getSource() == backButton)
		{
			back.goBack(back.getNumber());
		}
		else if(e.getSource() == btnPrint)
		{
			printCityPDF();
		}

		frameCityUI.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}

	private void printCityPDF()
	{
		if (allCitiesTable.getRowCount() > 0)
		{
			ArrayList<ArrayList<String>> list = new ArrayList<ArrayList<String>>();

			String columns [] = {  "#", "Name", "Country" };

			ArrayList<String> cityID = new ArrayList<String>();
			ArrayList<String> cityName = new ArrayList<String>();
			ArrayList<String> cityCountry = new ArrayList<String>();

			list.add(cityID);
			list.add(cityName);
			list.add(cityCountry);

			for(int i = 0; i < allCitiesTable.getRowCount(); i++)
			{
				list.get(0).add(String.valueOf(allCitiesTable.getValueAt(i, 0)));
				list.get(1).add(String.valueOf(allCitiesTable.getValueAt(i, 1)));
				list.get(2).add(String.valueOf(allCitiesTable.getValueAt(i, 2)));
			}

			PdfFilePrint pdfPrint = new PdfFilePrint();
			boolean successPDF = pdfPrint.PDFPrint("Cities", "Current Cities", "city", "Nikola", columns, list);

			if(successPDF)
				msgSuccess(null, "PDF was created successfully");
			else
				msgError(null, "There was an error creating the PDF");
		}
		else
		{
			msgError(null, "Nothing to print");
		}
	}

	private boolean checkInfo(JTextField textField)
	{

		if ((textField.getText().trim().length() == 0) || (textField.getText().trim().length() > 32))
			return false;

		return true;
	}

	private void addCity()
	{
		boolean validInfo = checkInfo(newCityName);

		if(validInfo)
		{
			try
			{
				int good = cityCtrl.addNewCity(newCityName.getText().trim(), countryCtrl.getOneCountry("name", newCityCountryComboBoxSearchType.getSelectedItem().toString()));

				if(good > 0)
				{
					msgSuccess(newCities, "City \"" + newCityName.getText() + "\" has been added successfully" );

					newCityName.setText(null);

					searchCities();
				} // end of if
				else if (good < 0)
				{
					msgError(newCities, "There was an error adding the city.\n");
				} // end of else

			} //end of try
			catch(Exception ex)
			{
				msgError(newCities, "There was an error adding the city.");
			} // end of catch
		} // end of if
		else{
			msgError(newCities, "You cannot proceed due to errors in your input.\nThe text area can not have more then 32 symbols or less then 1.");
		} // end of else
	}

	private void showEditCityDialog()
	{
		if(allCitiesTable.getSelectedRow() > -1)
		{
			int cityID = Integer.valueOf(String.valueOf(allCitiesTable.getValueAt(allCitiesTable.getSelectedRow(), 0)));
			City city = new City();
			try
			{
				city = cityCtrl.getOneCity("id", String.valueOf(cityID),newCityCountryComboBoxSearchType.getSelectedItem().toString() );
			} catch (SQLException e)
			{
				msgError(newCities, "Cannot retrieve the needed information");
				e.printStackTrace();
			}

			JPanel panel = new JPanel(new GridLayout(0,2,5,5));

			JTextField editCityName = new JTextField(city.getName());

			JComboBox <String> countryEdit = new JComboBox<String>();

			updateCountries(countryEdit);

			panel.add(new JLabel("City name:"));
			panel.add(editCityName);
			panel.add(new JLabel("Country:"));
			panel.add(countryEdit);

			int option = JOptionPane.showConfirmDialog(allCities, panel, "Edit city", JOptionPane.OK_CANCEL_OPTION);

			if(option == JOptionPane.YES_OPTION)
			{
				boolean validInfo = checkInfo(editCityName);
				if(validInfo)
				{

					Country country = new Country();
					try
					{
						country = countryCtrl.getOneCountry("name", countryEdit.getSelectedItem().toString());

					} catch (SQLException e)
					{
						msgError(allCities, "Cannot retrieve the needed information");
						e.printStackTrace();
					}

					int success = cityCtrl.updateCity(cityID,editCityName.getText(), country);

					if(success > 0)
					{
						msgSuccess(allCities, "City " + editCityName.getText() + " has been edited successfully");
						searchCities();
					} // end of if
					else
					{
						msgError(allCities, "There was an error while editing the city");
					} // end of else
				} // end of if
				else
				{
					msgError(allCities, "The information you have inserted is not correct, please try again");
				} // end of else
			} // end of if

		} // end of if
		else
		{
			msgError(allCities, "You have not selected a city");
		} // end of else
	}

	private void allCitiesUpdateTable(ArrayList<City> cityLister)
	{
		if(cityLister.size() > 0)
		{
			tableClearList();

			for(City city : cityLister)
			{
				allCitiesTableModel.addRow(
						new Object[]
								{
								city.getCityID(),
								city.getName(),
								city.getCountry().getName(),
								new ImageIcon("img/flags/" + city.getCountry().getTld() + ".png")
								}
						);

			} // end of for
		} // end of if
	}
	private void tableClearList()
	{
		DefaultTableModel dTM = (DefaultTableModel) allCitiesTable.getModel();

		while(dTM.getRowCount() > 0)
			dTM.removeRow(0);

	}
	public void searchCities()
	{
		ArrayList<City> cityListTwo = new ArrayList<City>();

		String clause = allCitiesComboBoxsearchType.getSelectedItem().toString().toLowerCase();
		String search = allCitiesSearch.getText();

		try
		{
			tableClearList();
			switch(clause)
			{
				case "everything" : cityListTwo = cityCtrl.getCitiesByAllInfo(search); break;
				case "name" : cityListTwo = cityCtrl.getCityByName(search); break;
				case "country" : cityListTwo = cityCtrl.getCitiesByCountryName(search); break;
			} // end of switch
			allCitiesUpdateTable(cityListTwo);
		} // end of try
		catch (Exception e)
		{
			msgError(allCities, "Could not load cities");
			e.printStackTrace();
		}

		if (!startup)
			startup = true;
	}

	private void msgError(JPanel panel, String error)
	{
		JOptionPane.showConfirmDialog(panel, error, "Error", JOptionPane.PLAIN_MESSAGE, JOptionPane.ERROR_MESSAGE);
	}

	private void msgSuccess(JPanel panel, String success)
	{
		JOptionPane.showMessageDialog(panel, success, "Success", 1);
	}

	public static CityUI getInstance()
	{
		if(instance == null)
			instance = new CityUI();

		return instance;
	}

	public static void main(String[] args)
	{
		try 
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 

			CityUI cityUI = new CityUI();
			cityUI.display();
		}
		catch(Exception e)
		{
			System.out.println("[ERROR] City Menu cannot load");
			e.printStackTrace();
		}
	}
}
